{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ![xtensor-io](images/xtensor-io.png)\n",
    "\n",
    "<center>Effortless loading of images, audio files and NumPy npz files!</center>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Usage\n",
    "\n",
    "<div style=\"background: #efffed;\n",
    "            border: 1px solid grey;\n",
    "            margin: 8px 0 8px 0;\n",
    "            text-align: center;\n",
    "            padding: 8px; \">\n",
    "    <i class=\"fa-play fa\" \n",
    "       style=\"font-size: 40px;\n",
    "              line-height: 40px;\n",
    "              margin: 8px;\n",
    "              color: #444;\">\n",
    "    </i>\n",
    "    <div>\n",
    "    To run the selected code cell, hit <pre style=\"background: #efffed\">Shift + Enter</pre>\n",
    "    </div>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <string>\n",
    "#include <fstream>\n",
    "\n",
    "#include \"xwidgets/ximage.hpp\"\n",
    "#include \"xwidgets/xslider.hpp\"\n",
    "\n",
    "#include \"xtensor/xview.hpp\"\n",
    "#include \"xtensor/xio.hpp\"\n",
    "\n",
    "#include \"xtensor-io/ximage.hpp\"\n",
    "#include \"xtensor-io/xaudio.hpp\"\n",
    "#include \"xtensor-io/xnpz.hpp\"\n",
    "\n",
    "#include \"xtl/xbase64.hpp\"\n",
    "\n",
    "#include \"xcpp/xdisplay.hpp\"\n",
    "\n",
    "namespace nl = nlohmann;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "std::vector<char> read_file(const char* filename)\n",
    "{\n",
    "    std::basic_ifstream<char> file(filename, std::ios::binary);\n",
    "    return std::vector<char>((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "template <class E>\n",
    "std::vector<char> to_png_buffer(const xt::xexpression<E>& e)\n",
    "{\n",
    "    const char* temp_filename = \"/tmp/xio_image.png\";\n",
    "    xt::dump_image(temp_filename, e);\n",
    "    return read_file(temp_filename);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Loading an image\n",
    "\n",
    "In the following an image is loaded from the file system, and then displayed using the above helper function.\n",
    "The slider can be used to make the lightsaber more-or-less xtensor-green!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "auto lightsaber = xt::load_image(\"images/saber.png\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "auto ls_image = xw::image();\n",
    "ls_image.value = to_png_buffer(lightsaber);\n",
    "ls_image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xt::xtensor<double, 3> lightsaber_modified;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "template <class E>\n",
    "void modify_image(xt::xexpression<E>& e, double value)\n",
    "{\n",
    "    lightsaber_modified = e.derived_cast();\n",
    "    double inc = value * 0.2;\n",
    "    xt::xtensor<double, 1> filter = {1. - inc, 1. + inc, 1. - inc};\n",
    "    lightsaber_modified *= filter;\n",
    "    ls_image.value = to_png_buffer(lightsaber_modified);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xw::slider<double> slider;\n",
    "slider.max = 5;\n",
    "slider.value = 2;\n",
    "slider.continuous_update = false;\n",
    "slider.display();\n",
    "\n",
    "XOBSERVE(slider, value, [](const auto& s) {\n",
    "    modify_image(lightsaber, s.value());\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Loading Audio\n",
    "\n",
    "In the next example a WAV file is loaded from the file system. The `load_audio` function returns a tuple, where the first value is the samplerate and the second value is an xarray holding the sound data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "auto swing = xt::load_audio(\"sounds/lightsaber_swing.wav\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "int sample_rate = std::get<0>(swing);\n",
    "auto audio_data = std::get<1>(swing);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "template <class E>\n",
    "auto player(const xt::xexpression<E>& e, int sample_rate, xeus::xguid id = xeus::xguid(), bool update = false)\n",
    "{\n",
    "    using namespace std::string_literals;\n",
    "    xt::dump_audio(\"/tmp/xio_audio.wav\", e, sample_rate);\n",
    "    std::ifstream fin(\"/tmp/xio_audio.wav\", std::ios::binary);\n",
    "    std::stringstream buffer;\n",
    "    buffer << fin.rdbuf();\n",
    "\n",
    "    nl::json mime;\n",
    "    mime[\"text/html\"] = std::string(\"<audio autoplay controls loop src=\\\"data:audio/wav;base64,\") + \n",
    "                        xtl::base64encode(buffer.str()) + \"\\\"/>\";\n",
    "    nl::json transient;\n",
    "\n",
    "    if (update)\n",
    "    {\n",
    "        transient[\"display_id\"] = id;\n",
    "        xeus::get_interpreter().update_display_data(\n",
    "            std::move(mime),\n",
    "            nl::json::object(),\n",
    "            std::move(transient));\n",
    "        return id;\n",
    "    }\n",
    "    else\n",
    "    {\n",
    "        id = xeus::new_xguid();\n",
    "        transient[\"display_id\"] = id;\n",
    "        xeus::get_interpreter().display_data(\n",
    "            std::move(mime),\n",
    "            nl::json::object(),\n",
    "            std::move(transient));\n",
    "        return id;\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "auto audio_id = player(std::get<1>(swing), sample_rate);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xw::slider<int> samplerate_slider;\n",
    "samplerate_slider.max = 50000;\n",
    "samplerate_slider.value = sample_rate;\n",
    "samplerate_slider.continuous_update = false;\n",
    "samplerate_slider.display();\n",
    "\n",
    "XOBSERVE(samplerate_slider, value, [](const auto& s) {\n",
    "    player(std::get<1>(swing), s.value(), audio_id, true);\n",
    "});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++14",
   "language": "C++14",
   "name": "xcpp14"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "c++",
   "version": "14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
